package cn.elwy.rcp.ui.util;

import java.io.File;
import java.io.InputStream;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.wb.swt.ResourceManager;

import cn.elwy.osgi.config.util.ThemeUtil;
import cn.elwy.rcp.core.model.ui.entity.Box;

/**
 * 获取图像工具类，可缓存图像信息
 * @author huangsq
 * @version 2.0, 2013-11-20
 * @since 2.0, 2013-11-20
 */
public class ImageUtil {

	private static final ImageRegistry imageRegistry = JFaceResources.getImageRegistry();
	public static final String HARDDISK = "/icons/harddisk_16.png";
	public static final String FOLDER = "/icons/folder_16.png";
	public static final String UNKNOWN_FILE = "/icons/unknown_16.png";

	// 将构造方法设置为private,禁止创建该类的实例
	private ImageUtil() {
	}

	/**
	 * 获取图像：首先从缓存中查找图像，如果没有则加载新的图像，并放入到缓存中。
	 * @param filePath 文件路径
	 * @return
	 */
	public static Image getImage(String filePath) {
		Image image = imageRegistry.get(filePath);
		if (image == null || image.isDisposed()) {
			image = ResourceManager.getImage(filePath);
			imageRegistry.put(filePath, image);// 将图像放到缓存中
		}
		return image;
	}

	/**
	 * 获取相对于类路径的图像
	 * @param clazz 类
	 * @param filePath 基于类的相对路径
	 * @return
	 */
	public static Image getImage(Class<?> clazz, String filePath) {
		String key = clazz.getName() + filePath;
		Image image = imageRegistry.get(key);
		if (image == null || image.isDisposed()) {
			image = ResourceManager.getImage(clazz, filePath);
			imageRegistry.put(key, image);// 将图像放到缓存中
		}
		return image;
	}

	/**
	 * 获取相对插件路径的图像
	 * @param pluginID 插件ID
	 * @param filePath 基于插件根目录的相对路径
	 * @return
	 */
	public static Image getImage(String pluginID, String filePath) {
		String key = pluginID + filePath;
		Image image = imageRegistry.get(key);
		if (image == null || image.isDisposed()) {
			image = ResourceManager.getPluginImage(pluginID, filePath);
			imageRegistry.put(key, image);// 将图像放到缓存中
		}
		return image;
	}

	/**
	 * 获取相对插件路径的主题图像
	 * @param pluginId 插件ID
	 * @param filePath 基于插件根目录的相对路径
	 * @return
	 */
	public static Image getImageByTheme(String pluginId, String filePath) {
		filePath = ThemeUtil.getThemeFilePath(filePath);
		return getImage(pluginId, filePath);
	}

	/**
	 * 获取图像描述符：首先从缓存中查找图像描述符，如果没有则加载新的图像描述符，并放到缓存中。
	 * @param filePath 文件路径
	 * @return
	 */
	public static ImageDescriptor getImageDescriptor(String filePath) {
		ImageDescriptor imageDescriptor = imageRegistry.getDescriptor(filePath + ".ImageDescriptor");
		if (imageDescriptor == null) {
			imageDescriptor = ResourceManager.getImageDescriptor(filePath);
			imageRegistry.put(filePath + ".ImageDescriptor", imageDescriptor);
		}
		return imageDescriptor;
	}

	/**
	 * 获取相对类路径的图像描述符
	 * @param clazz 类
	 * @param filePath 基于类的相对路径
	 * @return
	 */
	public static ImageDescriptor getImageDescriptor(Class<?> clazz, String filePath) {
		String key = clazz.getName() + filePath + ".ImageDescriptor";
		ImageDescriptor imageDescriptor = imageRegistry.getDescriptor(key);
		if (imageDescriptor == null) {
			imageDescriptor = ResourceManager.getImageDescriptor(clazz, filePath);
			imageRegistry.put(key, imageDescriptor);
		}
		return imageDescriptor;
	}

	/**
	 * 获取相对类路径的图像描述符
	 * @param clazz 类
	 * @param filePath 基于类的相对路径
	 * @return
	 */
	public static ImageDescriptor getImageDescriptor(String pluginId, String filePath) {
		String key = pluginId + filePath + ".ImageDescriptor";
		ImageDescriptor imageDescriptor = imageRegistry.getDescriptor(key);
		if (imageDescriptor == null) {
			imageDescriptor = ResourceManager.getPluginImageDescriptor(pluginId, filePath);
			imageRegistry.put(key, imageDescriptor);
		}
		return imageDescriptor;
	}

	/**
	 * 根据传入的实际宽度或高度计算出缩放后的高度或宽度
	 * @param width 原始宽度
	 * @param height 原始高度
	 * @param newWidth 新的宽度
	 * @return 新的高
	 */
	public static int getScaleLength(float width, float height, int newWidth) {
		float imageScale = (float) newWidth / (float) width;
		return Math.round(height * imageScale);
	}

	/**
	 * 根据传入的实际宽度或高度计算出缩放后的高度或宽度
	 * @param imgWidth 原始宽度
	 * @param imgHeight 原始高度
	 * @param newWidth 最大宽度
	 * @param newHeight 最大高度
	 * @param isOut 大于实际尺寸
	 * @return 实际宽度和高度
	 */
	public static Box getScaleSize(float imgWidth, float imgHeight, int newWidth, int newHeight, boolean isOut) {
		int realWidth = newWidth;
		int realHeight = getScaleLength(imgWidth, imgHeight, newWidth);

		if (isOut) {
			if (realHeight < newHeight) {
				realHeight = newHeight;
				realWidth = getScaleLength(imgHeight, imgWidth, newHeight);
			}
		} else {
			if (realHeight > newHeight) {
				realHeight = newHeight;
				realWidth = getScaleLength(imgHeight, imgWidth, newHeight);
			}
		}
		return new Box(0, 0, realWidth, realHeight);
	}

	/**
	 * 获得ImageData对象
	 * @param filePath 图像路径
	 * @return
	 */
	public static ImageData getImageData(String filePath) {
		return new ImageData(filePath);
	}

	/**
	 * 获得BufferedImage对象
	 * @param inputStream 图像流
	 * @return
	 */
	public static ImageData getImageData(InputStream inputStream) {
		return new ImageData(inputStream);
	}

	/**
	 * 根据实际的尺寸，缩放给定的图片
	 * @param image 要缩放的图像
	 * @param width 缩放后的宽度
	 * @param height 缩放后的高度
	 * @return
	 */
	public static ImageData zoomImage(ImageData imageData, int newWidth, int newHeight) {
		return zoomImage(imageData, newWidth, newHeight, true);
	}

	/**
	 * 根据实际的尺寸，缩放给定的图片
	 * @param imageData 要缩放的图像
	 * @param width 缩放后的宽度
	 * @param height 缩放后的高度
	 * @param isMagnify false 当尺寸大于实际尺寸时不缩放
	 * @return
	 */
	public static ImageData zoomImage(ImageData imageData, int newWidth, int newHeight, boolean isMagnify) {
		int width = imageData.width;
		int height = imageData.height;

		if (newWidth >= width && newHeight >= height && !isMagnify) {
			return (ImageData) imageData.clone();
		}

		return imageData.scaledTo(newWidth, newHeight);
	}

	/**
	 * 根据宽度计算高度，缩放给定的图片
	 * @param imageData 要缩放的图像
	 * @param width 缩放后的宽度
	 * @param height 缩放后的高度
	 * @param isMagnify false当尺寸大于实际尺寸时不缩放
	 * @return
	 */
	public static ImageData zoomImageByWidth(ImageData imageData, int newWidth, boolean isMagnify) {
		int width = imageData.width;
		int height = imageData.height;
		int newHeight = getScaleLength(width, height, newWidth);
		return zoomImage(imageData, newWidth, newHeight, isMagnify);
	}

	/**
	 * 根据高度计算宽度，缩放给定的图片
	 * @param imageData 要缩放的图像
	 * @param newHeight 缩放后的高度
	 * @param isMagnify false当尺寸大于实际尺寸时不缩放
	 * @return
	 */
	public static ImageData zoomImageByHeight(ImageData imageData, int newHeight, boolean isMagnify) {
		int width = imageData.width;
		int height = imageData.height;
		int newWidth = getScaleLength(height, width, newHeight);
		return zoomImage(imageData, newWidth, newHeight, isMagnify);
	}

	/**
	 * 根据长边自动计算实际的尺寸，缩放给定的图片
	 * @param image 要缩放的图像
	 * @param scale 缩放比例，正数表示放大负数表示缩小
	 * @param isMagnify false当尺寸大于实际尺寸时不缩放
	 * @return
	 */
	public static ImageData zoomImageByScale(ImageData imageData, int scale, boolean isMagnify) {
		int newWidth = imageData.width;
		int newHeight = imageData.height;

		if (scale > 0) {
			newWidth *= scale;
			newHeight *= scale;
		} else if (scale < 0) {
			newWidth /= scale;
			newHeight /= scale;
		}
		return zoomImage(imageData, newWidth, newHeight, isMagnify);
	}

	/**
	 * 根据长边自动计算实际的尺寸，缩放给定的图片
	 * @param image 要缩放的图像
	 * @param width 缩放后的宽度
	 * @param height 缩放后的高度
	 * @param isMagnify false当尺寸大于实际尺寸时不缩放
	 * @return
	 */
	public static ImageData zoomImageByLength(ImageData imageData, int length, boolean isMagnify) {
		int width = imageData.width;
		int height = imageData.height;

		int newWidth = length;
		int newHeight = length;
		if (width > height) {
			newHeight = getScaleLength(width, height, length);
		} else {
			newWidth = getScaleLength(height, width, length);
		}
		return zoomImage(imageData, newWidth, newHeight, isMagnify);
	}

	/**
	 * 根据实际的尺寸，缩放给定的图片，当图片尺寸小于实际尺寸时缩放
	 * @param imageData 要缩放的图像
	 * @param newWidth 新的图片宽度
	 * @param newHeight 新的图片高度
	 * @param isOut 大于实际尺寸
	 * @return
	 */
	public static ImageData zoomImageByWidthOrHeight(ImageData imageData, int newWidth, int newHeight, boolean isOut) {
		int width = imageData.width;
		int height = imageData.height;

		int realWidth = newWidth;
		int realHeight = getScaleLength(width, height, newWidth);

		if (isOut) {
			if (realHeight < newHeight) {
				realHeight = newHeight;
				realWidth = getScaleLength(height, width, newHeight);
			}
		} else {
			if (realHeight > newHeight) {
				realHeight = newHeight;
				realWidth = getScaleLength(height, width, newHeight);
			}
		}

		return zoomImage(imageData, realWidth, realHeight, true);
	}

	/**
	 * 保存指定的图像信息
	 * @param imageData 要保存的图像
	 * @param filePath 保存路径
	 * @return
	 */
	public static boolean saveImage(ImageData imageData, String filePath) {
		return saveImage(imageData, filePath, imageData.type);
	}

	/**
	 * 保存指定的图像信息
	 * @param imageData 要保存的图像
	 * @param filePath 保存路径
	 * @param filePath 图像格式
	 * @return
	 */
	public static boolean saveImage(ImageData imageData, String filePath, int format) {
		ImageLoader loader = new ImageLoader();
		loader.data = new ImageData[] { imageData };
		loader.save(filePath, format);
		return true;
	}

	/**
	 * 根据实际的尺寸，缩放给定的图片
	 * @param filePath 图片路径
	 * @param newWidth 新的图片宽度
	 * @param newHeight 新的图片高度
	 * @return
	 */
	public static Image getImage(String filePath, int newWidth, int newHeight, boolean isMagnify) {
		ImageData imageData = zoomImage(new ImageData(filePath), newWidth, newHeight, isMagnify);
		return new Image(Display.getDefault(), imageData);
	}

	/**
	 * 获取文件关联图标
	 * @param file 文件
	 * @return 文件的系统图标
	 */
	public static Image getProgramImage(File file) {
		if (file.getParent() == null) {
			return getImage(ImageUtil.class, HARDDISK);
		} else if (file.isDirectory()) {
			return getImage(ImageUtil.class, FOLDER);
		} else {
			Image iconImage = getProgramImage(file.getName());
			if (iconImage == null) {// 无系统关联图标
				iconImage = getImage(ImageUtil.class, UNKNOWN_FILE);
			}
			return iconImage;
		}
	}

	/**
	 * 获取文件关联图标
	 * @param fileName 文件名称
	 * @return 文件的关联图标，或为 null
	 */
	public static Image getProgramImage(String fileName) {
		int index = fileName.lastIndexOf(".");
		Image image = null;
		if (index != -1) {// 有扩展名
			String extension = fileName.substring(index).toLowerCase();// linux下分大小 写
			image = imageRegistry.get(extension);
			if (image == null || image.isDisposed()) {
				Program program = Program.findProgram(extension);
				if (program != null) {
					ImageData imageData = program.getImageData();
					if (imageData != null) {
						image = new Image(null, imageData, imageData.getTransparencyMask());
						imageRegistry.put(extension, image);
					}
				}
			}
		}
		return image;
	}

	/** 释放图像资源 */
	public static void dispose() {
		ResourceManager.disposeImages();
		imageRegistry.dispose();
	}

	/** 释放图像资源 */
	public static void dispose(String imageName) {
		imageRegistry.remove(imageName);
		imageRegistry.remove(imageName + ".ImageDescriptor");
	}

}
